Questions
1 of 11
1Evaluate this claim: 'Cosine similarity and normalized dot product always produce identical rankings.' What subtlety do candidates often miss here?
2Many candidates assume increasing ef at query time always improves recall with only a linear latency cost. What's misleading about that assumption?
3Why is 'just add more RAM' not always a valid answer to a Qdrant performance question in a system design interview?
4A candidate claims that quantization always speeds up search. Under what conditions might quantization with rescoring actually be slower than searching un-quantized vectors?
5Why can two identical-looking filter queries - one using an indexed field, one using an equivalent but unindexed field - have wildly different performance, even though they return the same results?
6At billion-point scale, how would your indexing and sharding strategy differ from a design that works fine at ten million points?
7How would you architect a system to gracefully degrade - rather than fail outright - when a burst of traffic exceeds provisioned Qdrant capacity?
8What are the limits of a purely payload-filter-based multitenancy model, and at what point would you need to introduce dedicated shards or collections per tenant instead?
9How would you approach re-embedding a multi-billion-point production collection with a new embedding model with zero search downtime?
10When designing a retrieval system that combines dense, sparse, and multivector reranking at extreme scale, what's the single biggest cost driver you'd optimize first, and why?
11If you were asked to design Qdrant's filtered-HNSW search from scratch, what core problem would you need to solve, and what naive approach would you reject first?
01 / 11

Evaluate this claim: 'Cosine similarity and normalized dot product always produce identical rankings.' What subtlety do candidates often miss here?

Equivalent only when both sides are truly unit-normalized

The claim is true only under a precise condition: both the query vector and every stored vector must be normalized to unit length. Cosine similarity is defined as dot(a, b) / (||a|| * ||b||). If both ||a|| and ||b|| are exactly 1, the denominator is 1 and cosine reduces to dot(a, b). The rankings are then identical. The subtlety that candidates miss is that this equivalence is conditional, and in practice the condition is often violated in ways that are invisible because the search still returns plausible results. The first violation is unnormalized query vectors: if the client normalizes documents at ingest but not queries, the query's norm is not 1, and cosine and dot will rank differently because the dot product scales with the query norm. The second violation is unnormalized stored vectors: if a single document's vector was not normalized (a bug in an ingest path, a partial batch, a manual upsert), that document's score is off by its norm and its ranking shifts. The third, more subtle violation is the storage metric: if the collection is created with Distance.DOT but the vectors were normalized, and the query is normalized, the rankings match cosine. But if the collection is created with Distance.COSINE, Qdrant normalizes at query time (or assumes normalized inputs), and the behavior differs from a DOT collection with unnormalized vectors. The fourth subtlety is that even when the rankings are identical in exact arithmetic, floating-point rounding can produce tiny differences that change the order of near-tied results, which matters for recall measurement but not for user experience.

The mechanism that makes this matter is that the equivalence is about the ordering of scores, not about the scores themselves. Cosine and dot produce the same ordering when both sides are normalized, but they produce different scores - cosine is bounded to [-1, 1] while dot is unbounded. If you compare a score threshold (e.g. 'only return results with similarity > 0.8'), the threshold means different things under the two metrics and can change which results are returned. This is why a system that switches from DOT to COSINE, or vice versa, can appear to 'work' while actually returning different top-k in edge cases. The practical implication is that the metric must be chosen deliberately and applied consistently: normalize everything and use DOT, or use COSINE and let the engine handle normalization, but do not mix. The other practical implication is that a test asserting on exact scores will fail when the metric changes even if the ranking is the same, so tests should assert on rankings, not on raw scores.

  1. 1

    Equivalence condition: both query and stored vectors normalized to unit length.

  2. 2

    Unnormalized query: dot scales with the query norm; cosine does not.

  3. 3

    Unnormalized stored vector: that document's ranking is wrong under dot.

  4. 4

    Metric mismatch: a DOT collection with normalized vectors and a COSINE collection behave differently at the boundaries.

  5. 5

    Score vs ranking: the rankings match, the scores do not; threshold filters behave differently.

  6. 6

    Floating-point: near-ties can be ordered differently under the two metrics.

  7. 7

    Recommendation: pick one metric, apply it consistently, and test on rankings not scores.

  8. 8

    Verification: check ||v|| for a sample of stored vectors and the query vectors.

The trade-off is between the simplicity of 'normalize everything and use dot' and the robustness of 'use cosine and let the engine normalize'. The first is faster (no normalization at query time) but requires discipline in the ingest path. The second is safer (the engine handles normalization) but adds a small per-query cost. In practice, most modern embedding models output normalized vectors, and using DOT is a common choice, but the ingest path must be verified. The common mistakes are: (1) assuming the equivalence is unconditional; (2) normalizing at ingest but not at query (or vice versa); (3) switching the metric without re-normalizing and not noticing because the results still 'look right'; (4) comparing scores across metrics as if they were comparable; (5) not testing the edge case of an unnormalized vector in an otherwise normalized collection. Version note: the behavior of Distance.COSINE and Distance.DOT, and whether the engine normalizes internally, has been stable across recent Qdrant releases but the details of the implementation may differ. Verify by testing with a known unnormalized vector.

javascript

Version-dependent: the exact behavior of Distance.COSINE (whether the engine normalizes both sides, one side, or assumes normalized input) is version-specific. In practice, Qdrant's cosine distance normalizes both sides, so the equivalence holds for the ranking, but the scores are cosine scores, not dot scores. Verify the behavior on your version by comparing the scores from a COSINE collection with the hand-computed cosine similarity.

Difficulty: 8/10
Topics: Distance Metrics, Normalization, Cosine Similarity

Scenario Questions

0-2 years experience
  1. 1

    You switch from cosine to dot product and the rankings change slightly. Explain why.

  2. 2

    A teammate says the two are always equivalent. Explain the condition under which they are.

2-5 years experience
  1. 1

    Your recall measurement differs between a COSINE and a DOT collection with the same vectors. Diagnose the cause and describe the fix.

  2. 2

    You need to verify that all stored vectors are normalized. Describe the check and how you would run it on a large collection.

5-8 years experience
  1. 1

    Design a test suite that catches unnormalized vectors and metric mismatches before they reach production.

  2. 2

    You are migrating from a COSINE collection to a DOT collection for performance. Describe the validation that ensures the ranking is unchanged.

8+ years experience
  1. 1

    Derive the exact condition under which the top-k under cosine and dot are guaranteed to be identical, including the case of ties.

  2. 2

    You are designing a system that must support both cosine and dot collections transparently. Describe the abstraction and the validation.

Follow-up Questions

  • How would you detect that a small fraction of stored vectors are unnormalized, without scanning the entire collection?
  • If you switch from DOT to COSINE, which parts of the system need to change, and how would you validate that the ranking is unchanged?